package com.easy.stock.spider.browser;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.FileUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxProfile;
import com.easy.stock.spider.Spider;
import com.easy.stock.util.OsUtil;

/**
 * 基于Selenium的基础Spider类
 * 
 * @author simonlin
 */
public abstract class BaseSeleniumSpider implements Spider {
	
	protected static Log LOG = LogFactory.getLog("spider");
	protected String currentBrowserProcessId=null;
	protected String currentProfilePath=null;
	protected WebDriver driver;
	
	protected String firefoxPath;
	protected int timeout=15; // 单位秒 
	
	protected void restartDriver() {
		System.setProperty("webdriver.firefox.bin", firefoxPath);
		Set<String> oldIDs = getBrowserPids();
		Set<String> oldProfiles = getProfileDirs();
		shutdownDriver();
		
		FirefoxProfile profile = new FirefoxProfile();
		profile.setPreference("browser.cache.disk.enable", false);
		profile.setPreference("browser.cache.memory.enable", false);
		profile.setPreference("browser.cache.offline.enable", false);
		profile.setPreference("network.http.use-cache", false);

		driver = new FirefoxDriver(profile);
		Set<String> newIDs = getBrowserPids();
		for(String id : newIDs) {
			if(!oldIDs.contains(id)) {
				currentBrowserProcessId = id;
				break;
			}
		}
		Set<String> newProfiles = getProfileDirs();
		for(String path : newProfiles) {
			if(!oldProfiles.contains(path)) {
				currentProfilePath = path;
				break;
			}
		}
		driver.manage().window().maximize();
		driver.manage().timeouts().pageLoadTimeout(timeout, TimeUnit.SECONDS);
		
//		HtmlUnitDriver  htmlDriver = new HtmlUnitDriver(BrowserVersion.FIREFOX_24);
//		htmlDriver.setJavascriptEnabled(true);
//		driver = (WebDriver)htmlDriver;
//		driver.manage().window().maximize();
	}
	
	
	protected void shutdownDriver() {
		if(OsUtil.isWindows())
			shutdownDriverInWindows();
		else if(OsUtil.isUnix())
			shutdownDriverInLinux();
		
		if(currentProfilePath!=null)
			FileUtils.deleteQuietly(new File(currentProfilePath));
	}
	
	private void shutdownDriverInWindows() {
		try {
			Runtime.getRuntime().exec("taskkill /pid "+currentBrowserProcessId+" /f");
		} catch (IOException e) {
			LOG.error("fail to kill old browser pid="+currentBrowserProcessId+", reason=", e);;
		}
	}
	
	private void shutdownDriverInLinux() {
		try {
			Runtime.getRuntime().exec(new String[] {"bash", "-c", "kill "+currentBrowserProcessId});
		} catch (IOException e) {
			LOG.error("fail to kill old browser pid="+currentBrowserProcessId+", reason=", e);;
		}
	}
		
	protected Set<String> getBrowserPids() {
		if(OsUtil.isWindows())
			return getBrowserPidsInWindows();
		if(OsUtil.isUnix())
			return getBrowserPidsInLinux();
		
		return Collections.emptySet();
	}
	
	protected Set<String> getProfileDirs() {
		String path = System.getProperty("java.io.tmpdir");
		File tempDir = new File(path);
		File files[] = tempDir.listFiles();
		Set<String> matches = new HashSet<String>();
		for(File file : files) {
			if(file.isDirectory() && file.getAbsolutePath().endsWith("webdriver-profile")) {
				matches.add(file.getAbsolutePath());
			}
		}
		return matches;
	}
	
	private Set<String> getBrowserPidsInWindows() {
		Set<String> ids = new HashSet<String>();
		try {
			Process process = Runtime.getRuntime().exec("wmic process get processid,parentprocessid,executablepath");
			BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
			String line=null;
			while( (line=reader.readLine())!=null ) {
				if(line.indexOf("firefox.exe")>0) {
					String fields[] = line.split("[\\s]+");
					String currentPid = fields[fields.length-1];
					ids.add(currentPid);
				}
			}
		} catch (IOException e) {
			LOG.error("get browser pids failed, reason=", e);
		}
		return ids;
	}
	
	private Set<String> getBrowserPidsInLinux() {
		Set<String> ids = new HashSet<String>();
		try {
			Process process = Runtime.getRuntime().exec(new String[] {"bash", "-c", "ps aux | grep \'[f]irefox\'"});
			BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
			String line=null;
			while( (line=reader.readLine())!=null ) {
				if(line.indexOf("firefox")>0) {
					String fields[] = line.split("[\\s]+");
					String currentPid = fields[1];
					ids.add(currentPid);
				}
			}
		} catch (IOException e) {
			LOG.error("get browser pids failed, reason=", e);
		}
		return ids;
	}
	
	protected void scrollToBottom() {
		JavascriptExecutor js = (JavascriptExecutor)driver;
        js.executeScript("window.scrollTo(0,Math.max(document.documentElement.scrollHeight," +
        			"document.body.scrollHeight,document.documentElement.clientHeight));");
	}
	
	public void setFirefoxPath(String firefoxPath) {
		this.firefoxPath = firefoxPath;
	}
	
	public void setTimeout(int timeout) {
		this.timeout = timeout;
	}
}
